Reggie! Sprite Images

This page will explain how to create custom sprite images for use with game patches.

Index

Use the following links to navigate this page:
How Hard will it Be?
Getting Started: Taking Screenshots
Editing Screenshots
Explanations of Important Variables and Functions
Creating a Basic Source Code File
Adding Basic Images
SpriteEditorItems
Advanced Images: Dynamic Sizers
Advanced Images: Custom Painters
Advanced Images: Auxiliary Images
Advanced Images: Other Auxiliary Items
Advanced Images: Liquid Painters


How Hard will it Be?

Generally, individual sprite images take a relatively short amount of time to make once you learn how. If you've retextured a sprite, you don't need to know anything about programming - just read the next two sections on this page. If you've changed the 3D models sprites use or edited them using ASM, you'll need to know how to program in Python.

Getting Started: Taking Screenshots

In order to add images of sprites to Reggie!, you need to first have images of sprites. The best way to get images of sprites is by taking screenshots of them with Dolphin Emulator. Assuming you have a retail copy of NSMBW and a Wii, you can obtain an ISO by ripping it with a tool such as CleanRip. You can then add and replace files using WIT (Wiimms ISO Tools) or WiiScrubber (not recommended).

Once you have a disc image with your custom sprite on it, you need to make a level specifically for taking an image of it. You can copy-and-paste the below ReggieClip into Reggie! for an example of how one of those levels might look:

ReggieClip|0:0:1:1:0:1:1:24|0:0:1:1:0:0:1:1|0:0:1:1:1:0:32:1|0:0:1:1:33:0:1:1|0:0:1:1:33:1:1:24|0:0:1:1:0:25:1:1|0:0:1:1:1:25:32:1|0:0:1:1:33:25:1:1|0:0:2:1:8:10:5:1|0:0:1:1:13:11:11:1|0:0:54:1:21:10:1:1|0:0:54:1:17:13:1:1|0:0:54:1:17:6:1:1|0:0:54:1:13:10:1:1|0:0:1:1:13:5:1:5|1:20:272:160:0:0:0:0:0:0:0|1:0:184:144:0:0:0:0:0:0:0|%

The zone border should be placed at the border indicated by the invisible blocks. The "sprite 0" should be replaced with the main entrance. The Goomba should be replaced with the sprite you want an image of. The background for this zone should be set to None, the zone theme should be set to "Overworld", and the zone lighting should be set to "Normal/Overworld".

The dark stone blocks are used as reference points to determine the exact spot at which the sprite will appear. They are needed because the rest of the level is made of invisible tiles to simplify the background removal which will happen later. The dark stone blocks can be placed at any distance from the sprite, but they should line up with it when "Show Sprite Images" is turned off.

Once you have a level set up, set it as 01-02.arc in your disc image. Don't use 01-01.arc because World 1-1 has hardcoded backgrounds. Open Dolphin and set it to the highest quality settings possible, including full-screen mode. It will probably be extremely slow, but your images will look much better. Go to World 1-2 (play 1-1 first if you need to).

Now you need to decide when to take the screenshot. In many cases you can do this at the instant the sprite becomes visible. In other cases, the sprite will be in an unappealing or unrepresentative pose at that moment, and you may need to wait several frames before taking the screenshot. Dolphin has options that allow you to slow down or pause the emulation to find the perfect frame. When you're satisfied, take the screenshot by pressing the "PrtSc" (Print Screen) key on your keyboard.

Now the screenshot is in the Windows clipboard. Open an image editor such as Paint.NET, GIMP or Photoshop, paste the image there and save it.

Editing Screenshots

Once you have a screenshot, you need to crop away the background and resize it to match Reggie!'s 100% zoom level. You can do this with any modern image editor (MS Paint won't work) such as Paint.NET, GIMP or Photoshop. Crop the background out by selecting the black area with a Magic Wand-like tool, using the highest tolerance setting you can without cutting into the sprite. Then, crop the image borders as close as possible to the edges of the sprite. Save it as a PNG within your game definition's sprites folder.

Resizing the image is much trickier than cropping the background. If you just retextured an sprite that has an image already in Reggie!, just use the dimensions of the original image and disregard the rest of this. If you took a screenshot of a brand-new sprite or 3D model, read on. If you took a high-resolution screenshot, your sprite image is several times larger than it needs to be. The surest way to find the exact dimensions is to take a second screenshot of the sprite for this sole purpose. This time, add reference tiles behind the sprite, like this:

ReggieClip|0:0:51:2:0:0:12:12|0:0:54:2:5:2:1:1|0:0:54:2:2:5:1:1|0:0:54:2:8:5:1:1|0:0:54:2:5:7:1:1|0:0:1:1:3:6:5:1|1:20:80:80:0:0:0:0:0:0:0|%

Add the stone blocks to Layer 2 of your screenshot level, and put it back into your disc image. Take another screenshot, but this time you don't need to use the highest quality settings. Try to capture the sprite at the same frame you took the first image, if possible. Count how many blocks high and wide the sprite is, and try to be as exact as possible. In Reggie!, each of those stone block tiles is exactly 24x24 pixels. Do some basic multiplication to find the final dimensions of your sprite image. Once you've done that, resize your image to those dimensions. Remember to save a backup copy of the high-resolution version!

Explanations of Important Variables and Functions

NOTE: The sprite image system has been recently redesigned. As such, all of the text from here on is outdated. This page will be rewritten at some point in the future.

If you already know how to program in Python, there are some important Reggie!-specific objects you need to know about.

  • Reggie! uses the PyQt library extensively for UI and image management.
  • Initialiser functions are functions that apply sprite image data to each sprite when they are created. There is generally one for every sprite type with images. Each one takes one argument, sprite, which is the SpriteEditorItem it acts upon.
  • ImageCache is a global dictionary. It contains all sprite images that have been loaded by the editor thus far since launch. This speeds up the editor, because each PNG only needs to be loaded once, and can be reused many times. Each key is a string that is the name of the sprite, generally.
  • Initialisers is a global dictionary. It contains every initialiser function, with each key being the sprite number as an integer. Reggie! uses this to find initialiser functions.
  • GetImg is a function. It returns the QtGui.QPixmap data for any sprite image PNG file. Its only required argument is a string matching the filename of the PNG. A second, optional argument, if set to True, will force the function to return the data in the form of a QtGui.QImage rather than a QPixmap. You must use this function rather than QtGui.QPixmap.open() because this function is compatible with cascading game patches, whereas QtGui.QPixmap.open() is not.
  • SpriteEditorItems are objects that represent individual sprites. Each time an initialiser function is called, it is given a SpriteEditorItem as an argument, and the initialiser function applies sprite image data to it.
  • Custom painters are functions that repaint sprites when their sprite data changes. They take both a SpriteEditorItem and a QtGui.QPainter as arguments. The QPainter paints to the position on the canvas of the sprite, and the SpriteEditorItem gives you access to the current sprite data and settings of the sprite.
  • Dynamic sizers are functions that resize sprite selection boundaries when sprite data changes. They take a SpriteEditorItem as an argument, and are very similar in use to custom painters.

Creating a Basic Source Code File

Sprite image source code files have a basic structure that keeps functions organized. The order is:

  1. Initialiser functions
  2. The Initialisers dictionary
  3. Dynamic sizers
  4. Custom painters

Within each of these sections, the functions/data are arranged by sprite number, from lowest to highest. Sprites which are not affected by your game patch are skipped.

To make a basic source code file, then, create a text file named sprites.py and put it into your game patch's folder. (Make sure to update main.xml to reflect this.) Add a few lines of comments at the beginning to specify your name and what game you're patching. Then add a basic Initialisers dictionary:

Initialisers = {
    }

You will add to this dictionary as you add more sprite images.

Adding Basic Images

To make a basic image appear in Reggie!, start by adding the following code to the Initialisers portion of sprites.py:

def InitSpriteName(sprite): # SpriteNumber
    global ImageCache
    if 'SpriteName' not in ImageCache:
        ImageCache['SpriteName'] = GetImg('ImageFilename')

    sprite.customPaint = True
    sprite.customPainter = PaintGenericObject
    sprite.image = ImageCache['SpriteName']
    return (AdjustedImagePlacement)

Hopefully you have some idea of what this code does. Of course, you need to make some changes to this in order for it to work. Replace every instance of SpriteName with the name of your sprite. Then, replace SpriteNum with the number of your sprite. Replace ImageFilename with the filename of your image (for example, "goomba.png").

The AdjustedImagePlacement section is the hardest part. Ultimately, you should have 4 numbers separated by commas between the parentheses after return. The first 2 represent image position, and the second 2 represent image size. The two numbers for image size (width and height) are scaled by a factor of 2/3. Thus, if you had an image of actual size 100x200 pixels (width x height), you would choose 67 and 133 as your third and fourth numbers.

The first 2 numbers require trial and error to be found. They affect the position of the sprite image relative to the (invisible) blue sprite box. The first affects horizontal position and the second affects vertical position. You are allowed to use negative numbers, and you will use them for most sprite images. Pick something, and see how it looks in Reggie!. 0 is a good place to start. Change it by 10 and see how that affects the image. Adjust it until it matches the screenshot you took with the stone blocks on layer 2.

To clarify, the final line of your function should look something like this:

    return (-1,-4,18,20)

but with different numbers. The first 2, affecting image position, can be positive or negative, but the second 2, affecting image size, should always be positive.

After adding the initialiser function, you need to add an entry to the Initialisers dictionary so Reggie! can find it. Between the braces, add a new line:

    SpriteNumber: InitSpriteName,

Replace SpriteNumber with your sprite's number, and replace SpriteName with your sprite's name. If and when you add images for more sprites, arrange the contents of the Initialisers dictionary by sprite number, from lowest to highest.

SpriteEditorItems

SpriteEditorItems are objects that represent individual sprites. They contain sprite data, positions and image data. Most advanced sprite images alter SpriteEditorItems directly, so a section on their properties is needed.

SpriteEditorItems have the following relevant properties:

  • SpriteEditorItem.aux sets this sprite's auxiliary item. Auxiliary items are described later on this page.
  • SpriteEditorItem.customLocPaint is a boolean value which determines if the sprite needs a custom painter function to paint to locations.
  • SpriteEditorItem.customLocPainter is a function (or None) that Reggie! will call with the relevant location and painter if customLocPaint == True.
  • SpriteEditorItem.hasCrest is a boolean value which determines if the sprite's liquid image should include a crest. Has no effect if neither isLocPaintableLiquid nor isZonePaintableLiquid is True.
  • SpriteEditorItem.image sets the QPixmap which will be drawn to the canvas inside the selection boundaries. If this is set to None, a blue sprite box of the size specified by the SpriteEditorItem's width and height properties will be drawn.

  • SpriteEditorItem.isLocPaintableLiquid is a boolean value which determines if the sprite should cause liquid to be automatically painted within a location. If this is set to True, Reggie! will use the sprite's LiquidPix and LiquidCrestPix to paint the liquid.

  • SpriteEditorItem.isZonePaintableLiquid is a boolean value which determines if the sprite should cause liquid to be painted within a zone. If this is set to True, Reggie! will use the sprite's LiquidPix and LiquidCrestPix to paint the liquid.

  • SpriteEditorItem.LiquidPix is a pixmap that Reggie! uses to paint the non-crest portion of a liquid if it needs to.
  • SpriteEditorItem.LiquidCrestPix is a pixmap that Reggie! uses to paint the crest of a liquid if it needs to.
  • SpriteEditorItem.LiquidRisePix is a pixmap that Reggie! uses to indicate that a liquid without a crest will rise or fall to a certain height.
  • SpriteEditorItem.LiquidRiseCrestPix is a pixmap that Reggie! uses to indicate that a liquid with a crest will rise or fall to a certain height.
  • SpriteEditorItem.locIdAffected is an integer which determines the location ID that the sprite will paint to.
  • SpriteEditorItem.risingHeight is an integer which determines how many pixels the sprite's liquid will rise or fall. 24px = 1 block.
  • SpriteEditorItem.spritedata is a 8-character string that contains the sprite data. Each byte is in the form of a character. You can access a byte by indexing it (1st character is index 0, remember) and calling ord() on the character to get an integer. Then, perform some bitwise operations such as >> 4 and & 0xF to access individual halves of the byte if you want.
  • SpriteEditorItem.type is an integer that determines the sprite's sprite number. Don't edit this value.
  • SpriteEditorItem.xoffset controls the image's X-position offset relative to the sprite position.
  • SpriteEditorItem.yoffset does the same thing in the Y dimension.
  • SpriteEditorItem.xsize controls the width of the image, with 16 being one block wide.
  • SpriteEditorItem.ysize does the same thing with height.

Advanced Images: Dynamic Sizers

One important component of advanced images is dynamic sizers. Most sprites having images that change based on sprite data use dynamic sizers to accomplish this. Some use custom painters as well.

A dynamic sizer is a function that takes one SpriteEditorItem as an argument. It does not return anything in particular. All dynamic sizers appear in numerical order just after the Initialisers dictionary. They can access sprite data via the SpriteEditorItem and change the SpriteEditorItem's image settings (xoffset, yoffset, xsize, ysize, image, aux) based on the spritedata (accessed via sprite.spritedata as described above).

Advanced Images: Custom Painters

Custom painters are very similar to dynamic sizers. Custom painters can do anything dynamic sizers can do and vice-versa, but custom painters are intended for more complicated painting operations. Look at a reference guide of QPainter and QPixmap for a guide of how to use those, and they otherwise work similarly to dynamic sizers. The arguments are in the order (sprite, painter).

Advanced Images: Auxiliary Images

Auxiliary images are images that are attached to sprites, but are not necessarily included within the selection boundaries. A common example of this is the goal flagpole. The castle is an auxiliary image.

Auxiliary images are represented by Reggie!'s built in AuxiliaryImage class. To create one, perform an operation like this:

    aux = AuxiliaryImage(sprite, 256, 256) # The image is 256x256
    aux.image = ImageCache['SomeImage'] # Replace SomeImage with an actual key
    sprite.aux = aux

In some cases, you may want to also set aux.hover. It's a boolean value defaulting to True that determines if Reggie! should display sprite information in the status bar when the mouse hovers over the image. In many cases, such as when auxiliary images are used to provide a "glow" effect, this is better set to False.

Advanced Images: Other Auxiliary Items

In addition to auxiliary images, you can set SpriteEditorItem.aux to any of the following types:

  • AuxiliaryTrackObject creates a line with a stopper on each end. A well-known example of this is in horizontally-moving and vertically-moving platforms. It is created with (sprite, width, height, direction). Direction can be either 1 or 2 for horizontal and vertical lines, respectively.
  • AuxiliaryCircleOutline creates a circle. A well-known example of this is in Rolling Hills. It is created with (sprite, width).
  • AuxiliaryRotationAreaOutline creates a piece-of-pizza-shaped sector. A well-known example of this is in sprite 96, "Rotation Controller - Swaying." It is called with (sprite, width). You can set the rotation angle by calling AuxiliaryRotationOutline.SetAngle(startAngle, spanAngle).
  • AuxiliaryRectOutline creates a rectangle. A well-known example of this is in the Special Exit Controller. It is called with (sprite, width, height, xoffset, yoffset) as arguments. xoffset and yoffset are optional. You can set the rectangle size (and position) by calling AuxiliaryRectOutline.SetSize(width, height, xoffset, yoffset). xoffset and yoffset are optional.
  • AuxiliaryPainterPath creates an arbitrary shape determined by a QtGui.QPainterPath. An example of this is in the King Bill. It is called with (sprite, painterpath, width, height). QPainterPaths let you define any shape you want, comprised of lines, arcs and polygons.

Auxiliary items can be adjusted by dynamic sizers and custom painters.

Advanced Images: Liquid Painters

By setting various properties of SpriteEditorItem, you can instruct Reggie! to paint a liquid in a zone or location. The relevant properties of SpriteEditorItem are described above in the section about them. Set the correct settings in a dynamic sizer if you would like to do this.